/*
	Copyright (C) 2019 Zongming Liu <1849059316@qq.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef Object_h__
#define Object_h__

#include <cassert>
#include <list>

namespace SkyEngine2d
{
	
	template<typename T>
	class Object
	{
	public:
		virtual ~Object();
	
		void addChildren(T* children);
	
		void removeChildren(T* children);
	
		void setParent(T* parent);
	
		T* getParent()const;
	
		virtual bool init();
	protected:
		Object(T * parent = nullptr);
	
		T* m_parent;
		std::list<T*> m_childrenList;
		
	private:
		T* m_self;
	};
	
	template<typename T>
	bool Object<T>::init()
	{
		m_self = dynamic_cast<T*>(this);
		assert(m_self);
	
		this->setParent(m_parent);
	
		return true;
	}
	
	template<typename T>
	void Object<T>::addChildren(T* children)
	{
		m_childrenList.push_back(children);
	}
	
	template<typename T>
	void Object<T>::removeChildren(T* children)
	{
		children->m_parent = nullptr;
		m_childrenList.remove(children);
	}
	
	template<typename T>
	void Object<T>::setParent(T* parent)
	{
		if (m_parent)
		{
			m_parent->removeChildren(m_self);
		}
	
		m_parent = parent;
	
		if (parent)
		{
			parent->addChildren(m_self);
		}
	}
	
	template<typename T>
	T* Object<T>::getParent() const
	{
		return m_parent;
	}
	
	template<typename T>
	Object<T>::Object(T * parent /*= nullptr*/)
		:m_parent(parent)
		,m_self(nullptr)
	{
	}
	
	template<typename T>
	Object<T>::~Object()
	{
		if (m_parent)
		{
			m_parent->removeChildren(m_self);
		}
	
		auto temp = m_childrenList;
	
		for (auto& p : temp)
		{
			assert(p);
			if (p)
			{
				delete p;
			}
		}
	}
	
}

#endif // Object_h__
